import java.net.*;
import java.io.*;
import java.util.Scanner;

//sThread extends the thread class and is used to handle multiple connections to the server
public class sThread extends Thread{
	private Socket sock=null;
	SepereServer main;
	Peer newP;
	
	public sThread(Socket socket, SepereServer s)
	{
		super("sThread");
		this.sock = socket;
		this.main = s;
		System.out.println("Connection received from " + sock.getInetAddress().getHostAddress());
		newP = new Peer();
		newP.ipAddress = sock.getInetAddress();
		newP.superPeer = false; // set to false until we implement superpeer code
		newP.throughput = 0; // set to 0 until we implement superpeer code
		//do not use the socket in the peer object since that is only for clients to use
		main.addPeer(newP);
		
	}
	
	 public static byte[] hexToByte(String s) {
		    int len = s.length();
		    byte[] data = new byte[len / 2];
		    for (int i = 0; i < len; i += 2) {
		        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
		                             + Character.digit(s.charAt(i+1), 16));
		    }
		    return data;
		}
	 
	public void run()
	{
		try{
			PrintWriter out = new PrintWriter(sock.getOutputStream(),true);
		    BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

		    String inputLine;
		    Scanner s = null;
		    String cType = "";
		    
		    
		    while ((inputLine = in.readLine()) != null) {
		    	//System.out.println(inputLine);
		    	s = new Scanner(inputLine).useDelimiter("\\s*;\\s*");
		    	while(s.hasNext())
		    	{
		    		cType=s.next();
		    		if(cType.equals("class:Search"))
		    		{
		    			//format the search and pass to the main function
		    			Search newS = new Search(s.next());
		    			newS.searchHash = hexToByte(s.next());
		    			//send the search results back to the user
		    			System.out.println("Starting Search: "+newS.sText);
		    			out.println(main.search(newS));
		    			out.println("done");
		    		}
		    		else if(cType.equals("class:User"))
		    		{
		    			//add a new user to the list
		    			User newU = new User();
		    			newU.name = s.next();
		    			newU.email = s.next();
		    			newU.userID = s.next();
		    			newU.currentIP = InetAddress.getByName(s.next().substring(1));
		    			//newU.setHash(s.next().getBytes());
		    			newU.pass=s.next();
		    			System.out.println(newU.toString());
		    			main.addUser(newU);
		    		}
		    		else if(cType.equals("class:aFile"))
		    		{
		    			//add a new file that the user can search
		    			aFile newF = new aFile();
		    			newF.name = s.next();
		    			newF.size = Integer.parseInt(s.next());
		    			newF.Peer = s.next();
		    			newF.shortAbstract = s.next();
		    			newF.setHash(hexToByte(s.next()));
		    			//probably need to check that this is a new aFile
		    			//i.e. has not been uploaded already
		    			main.addFile(newF);
		    		}
		    		else if(cType.equals("login"))
		    		{
		    			out.println(main.logIn(s.next(),s.next()));
		    		}
		    		//if we recieve this msg we need to toggle superPeer status on
		    		else if(cType.equals("superPeer"))
		    		{
		    			this.newP.superPeer=true;
		    		}
		    		//send this message when we switch to distributed mode
		    		else if(cType.equals("distributed")){
		    			//if we are distributed assign super peer to this peer unless it is a superpeer
		    			main.dist=true;
			    		if(!this.newP.superPeer)
			    		{
			    			Peer p = main.assignPeer();
			    			if(p!=null)//if null we do not need to change since there are no superPeers
			    			{
			    				Boot b = new Boot(); //create a new boot object to send back to the peer
			    				b.server=p.ipAddress;
			    				b.port=4443;
			    				out.println(b.toString());
			    			}
			    			else//no super peer so leave the boot as the parent until a super declares itself
			    				out.println("NO SUPERPEERS");
			    		}
		    		}
		    		else if(cType.equals("spList"))
		    		{
		    			for(int i =0;i<main.peerList.size();i++)
		    			{
		    				//send back all super peers one at a time that the server knows about
		    				//we need the spList when we send out search request
		    				out.println(main.peerList.get(i).toString());
		    			}
		    			out.println(";done;");
		    		}
		    		
		    	}

		    	if (inputLine.equals("Quit"))
		    	{
		    		System.out.println("Connection Ended from " + sock.getInetAddress().getHostAddress());
		    		//remove peer from the peerList
		    		main.removePeer(sock.getInetAddress());
		    		break;
		    	}
		    		
		    	}
	    out.close();
	    in.close();
	    sock.close();
	} catch (IOException e) {
	    e.printStackTrace();
	}
	}

}
